package com.xzzz.irda.tracker.core.adapter.gateway;

import com.xzzz.irda.tracker.core.SpanContext;
import com.xzzz.irda.tracker.core.Tracker;
import com.xzzz.irda.tracker.core.TrackerUtil;
import com.xzzz.irda.tracker.core.common.TrackerConstants;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * Trace 全局过滤器
 */
public class TrackerGlobalFilter implements GlobalFilter, Ordered {

    public static final String TRACKER_TRACE_ID = "TRACKER_TRACE_ID";
    public static final String TRACKER_SPAN_ID = "TRACKER_SPAN_ID";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String traceName = request.getURI().getPath();

        Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        if (route != null) {
            traceName = route.getId() + ":" + traceName;
        }

        SpanContext spanContext = null;
        ServerHttpRequest.Builder mutateRequest = request.mutate();
        try {
            spanContext = Tracker.start(traceName, TrackerConstants.SPAN_TYPE_HTTP_GATEWAY);

            exchange.getAttributes().put(TRACKER_TRACE_ID, Tracker.getTraceId());
            exchange.getAttributes().put(TRACKER_SPAN_ID, Tracker.getSpanId());

            mutateRequest.header(TrackerConstants.HTTP_HEADERS, TrackerUtil.buildHeader(TrackerConstants.SPAN_TYPE_HTTP_GATEWAY_INVOKE));

            return chain.filter(exchange.mutate().request(mutateRequest.build()).build());
        } finally {
            if (spanContext != null) {
                Tracker.end();
            }
        }
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE;
    }
}
